Quick start
This example calculates the prayer times for Jakarta on 12 July 2026 using the KEMENAG (Indonesia) method and prints each time as HH:MM.
Add the dependency
cargo add libmuslim-rs
Remember that the package is libmuslim-rs and the library you import is libmuslim. A C compiler must be available at build time, because the crate compiles the vendored libmuslim sources itself.
The program
use libmuslim::prayertimes::{CalculationMethod, Coordinates, Date, MethodParams, calculate};
use libmuslim::timezone::offset_at;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Validate the inputs. Each constructor rejects out-of-range values,
// so an impossible date or latitude fails here rather than silently
// producing a wrong time later.
let date = Date::new(2026, 7, 12)?;
let jakarta = Coordinates::new(-6.2088, 106.8456)?;
let params = MethodParams::for_method(CalculationMethod::Kemenag)?;
// 2. Resolve the UTC offset for a zone at an instant, daylight saving
// already applied. Skip this if you already know the offset.
let offset = offset_at("Asia/Jakarta", 1_784_073_600)?;
// 3. Calculate.
let times = calculate(date, jakarta, offset, ¶ms)?;
println!("Fajr {}", times.fajr.format_hm());
println!("Dhuhr {}", times.dhuhr.format_hm());
println!("Asr {}", times.asr.format_hm());
println!("Maghrib {}", times.maghrib.format_hm());
println!("Isha {}", times.isha.format_hm());
Ok(())
}
Run it
cargo run
Fajr 04:44
Dhuhr 12:01
Asr 15:23
Maghrib 17:54
Isha 19:09
Times depend on the calculation method, the location and the offset. Change any of them and the output changes.
Supplying the offset yourself
The timezone module is optional. If you already know the offset, construct it directly and drop the dependency on the host time zone database:
use libmuslim::prayertimes::UtcOffset;
let offset = UtcOffset::from_hours(7.0)?;
from_hours takes a possibly fractional number of hours, so zones such as UTC+5:45 are expressed as 5.75. It rejects anything non-finite or outside the range -24 to 24.
Resolving the offset for right now
offset_at takes an instant as Unix epoch seconds, so the current offset comes from the system clock:
use std::time::{SystemTime, UNIX_EPOCH};
use libmuslim::timezone::offset_at;
let now = i64::try_from(SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs())?;
let offset = offset_at("Asia/Jakarta", now)?;
Passing the instant explicitly rather than reading the clock internally is what makes the offset correct for a date other than today. Prayer times for a date six months away need that date's offset, not the current one, and in a zone that observes daylight saving those differ.
Handling errors
Every fallible call returns a Result with a typed error, so you can match on the cause instead of parsing a message:
use libmuslim::prayertimes::{Coordinates, Error};
match Coordinates::new(91.0, 0.0) {
Ok(coordinates) => println!("{coordinates:?}"),
Err(Error::InvalidCoordinates { latitude, longitude }) => {
eprintln!("out of range: {latitude}, {longitude}");
}
Err(other) => eprintln!("{other}"),
}
Both prayertimes::Error and timezone::TimezoneError implement std::error::Error, so ? into Box<dyn Error> or any error type built with thiserror or anyhow works without a manual conversion.
Both enums are #[non_exhaustive]. A match on them needs a catch-all arm, which is what lets new variants be added without breaking your build.
See the API reference for the full list of types and functions.